package cur.nature.framework.core.util;

import cur.nature.framework.core.consts.NumConst;
import cur.nature.framework.core.exception.SystemException;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class MathUtil {
    /**
     * 构造函数.
     */
    private MathUtil() {
    }

    /**
     * 正确的相等比较.
     * @param a 数值a.
     * @param b 数值b.
     * @return 是否相等.
     */
    public static boolean equal(final BigDecimal a, final BigDecimal b) {
        return equal(a, b, 2);
    }

    /**
     * 正确的相等比较.
     * @param a 数值a.
     * @param b 数值b.
     * @param scale 精度.
     * @return 是否相等.
     */
    public static boolean equal(final BigDecimal a, final BigDecimal b, final int scale) {
        if (a == null && b == null) {
            return true;
        }

        if (a == null || b == null) {
            return false;
        }

        final BigDecimal v1 = a.setScale(scale, BigDecimal.ROUND_HALF_UP);
        final BigDecimal v2 = b.setScale(scale, BigDecimal.ROUND_HALF_UP);
        return v1.equals(v2);
    }

    /**
     * 正确的相等比较(将null当做0).
     * @param a 数值a.
     * @param b 数值b.
     * @param scale 精度.
     * @return 是否相等.
     */
    public static boolean equalZero(final BigDecimal a, final BigDecimal b, final int scale) {
        final BigDecimal a1 = handleNull(a);
        final BigDecimal b1 = handleNull(b);
        final BigDecimal v1 = a1.setScale(scale, BigDecimal.ROUND_HALF_UP);
        final BigDecimal v2 = b1.setScale(scale, BigDecimal.ROUND_HALF_UP);
        return v1.equals(v2);
    }

    /**
     * 处理BigDecimal的null情况.
     * @param val 值.
     * @return 处理后的值.
     */
    private static BigDecimal handleNull(final BigDecimal val) {
        if (val == null) {
            return BigDecimal.ZERO;
        }
        return val;
    }

    public static boolean equal(final int a, final int b) {
        final int result = compare(a, b);
        return result == 0 ? true : false;
    }

    public static boolean equal(final long a, final long b) {
        final int result = compare(a, b);
        return result == 0 ? true : false;
    }

    public static int compare(final int a, final int b) {
       return compare(Integer.valueOf(a), Integer.valueOf(b));
    }

    public static int compare(final Integer a, final Integer b) {
        if (a == null && b == null) {
            return NumConst.P0;
        }

        if (a == null) {
            return NumConst.N1;
        }

        if (b == null) {
            return NumConst.P1;
        }

        return a.compareTo(b);
    }

    public static int compare(final long a, final long b) {
        return compare(Long.valueOf(a), Long.valueOf(b));
    }

    /**
     * 正确的比较.
     * @param a 数值a.
     * @param b 数值b.
     * @param scale 精度.
     * @return a大于1返回1 a=b返回0 a小于b返回-1.
     */
    public static int compare(final Long a, final Long b) {
        if (a == null && b == null) {
            return NumConst.P0;
        }

        if (a == null) {
            return NumConst.N1;
        }

        if (b == null) {
            return NumConst.P1;
        }
        return a.compareTo(b);
    }


    /**
     * 正确的比较.
     * @param a 数值a.
     * @param b 数值b.
     * @param scale 精度.
     * @return a大于1返回1 a=b返回0 a小于b返回-1.
     */
    public static int compare(final BigDecimal a, final BigDecimal b,
                                        final int scale) {
        if (a == null && b == null) {
            return NumConst.P0;
        }

        if (a == null) {
            return NumConst.N1;
        }

        if (b == null) {
            return NumConst.P1;
        }

        final BigDecimal v1 = a.setScale(scale, BigDecimal.ROUND_HALF_UP);
        final BigDecimal v2 = b.setScale(scale, BigDecimal.ROUND_HALF_UP);
        return v1.compareTo(v2);
    }

    /**
     * 正确的比较.
     * @param a 数值a.
     * @param b 数值b.
     * @param scale
     *            精度.
     * @return a大于1返回1 a=b返回0 a小于b返回-1.
     */
    public static int compareZero(final BigDecimal a,
                                            final BigDecimal b, final int scale) {
        final BigDecimal a1 = handleNull(a);
        final BigDecimal b1 = handleNull(b);
        final BigDecimal v1 = a1.setScale(scale, BigDecimal.ROUND_HALF_UP);
        final BigDecimal v2 = b1.setScale(scale, BigDecimal.ROUND_HALF_UP);
        return v1.compareTo(v2);
    }

    /**
     * 设置BigDecimal的精度.
     * @param d 数值
     * @param scale 精度
     * @return 转换后的数值
     */
    public static BigDecimal setScale(final BigDecimal d, final int scale) {
        if (scale < 0) {
            return d;
        }

        return d.setScale(scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 是否大于0.
     * @param decimal 数值.
     * @return 大于0.
     */
    public static boolean thanZero(final BigDecimal decimal) {
        return compare(decimal, BigDecimal.ZERO, NumConst.P2) > NumConst.P0;
    }

    /**
     * 是否大于0.
     * @param decimal 数值.
     * @return 大于0.
     */
    public static boolean thanZeroZero(final BigDecimal decimal) {
        return compareZero(decimal, BigDecimal.ZERO, NumConst.P2) > NumConst.P0;
    }

    /**
     * BigDecimal相加.
     * @param decimal1 数1
     * @param decimal2  数2
     * @return 结果.
     * */
    public static BigDecimal add(final BigDecimal decimal1,
                                 final BigDecimal decimal2) {
        if (decimal1 == null && decimal2 == null) {
            return BigDecimal.ZERO;
        }

        if (decimal1 == null) {
            return decimal2;
        } else if (decimal2 == null) {
            return decimal1;
        } else {
            return decimal1.add(decimal2);
        }
    }

    /**
     * BigDecimal相减.
     * @param decimal1 数1
     * @param decimal2 数2
     * @return 结果.
     * */
    public static BigDecimal subtract(final BigDecimal decimal1,
                                      final BigDecimal decimal2) {
        if (decimal1 == null && decimal2 == null) {
            return BigDecimal.ZERO;
        }

        if (decimal1 == null) {
            return BigDecimal.ZERO.subtract(decimal2);
        } else if (decimal2 == null) {
            return decimal1;
        } else {
            return decimal1.subtract(decimal2);
        }
    }

    /**
     * BigDecimal相减.
     * @param decimal1 数1
     * @param decimal2 数2
     * @return 结果.
     * */
    public static BigDecimal mul(final BigDecimal decimal1, final BigDecimal decimal2) {
        if (decimal1 == null || decimal2 == null) {
            return BigDecimal.ZERO;
        }

        return decimal1.multiply(decimal2);
    }


    /**
     * BigDecimal相减.
     * @param decimal1  数1
     * @param decimal2 数2
     * @return 结果.
     * */
    public static BigDecimal div(final BigDecimal decimal1,
                                 final BigDecimal decimal2) throws SystemException {
        return div(decimal1,decimal2,RoundingMode.HALF_UP);
    }

    /**
     * BigDecimal相减.
     * @param decimal1  数1
     * @param decimal2 数2
     * @return 结果.
     * */
    public static BigDecimal div(final BigDecimal decimal1,
                                 final BigDecimal decimal2, RoundingMode roundingMode) throws SystemException {
        if (equalZero(BigDecimal.ZERO, decimal2, NumConst.P2)) {
            throw new SystemException("被除数为null或者0");
        }

        if (equalZero(BigDecimal.ZERO, decimal1, NumConst.P2)) {
            return BigDecimal.ZERO;
        }

        return decimal1.divide(decimal2, roundingMode);
    }
}
